package ai;

import java.util.ArrayList;
import java.util.List;

import spel.Bord;
import spel.Knikker;
import spel.Spel;
import spel.Zet;

public class PuntenStrategie implements Strategie {
	private int timeout = 0;
	private List<Knikker> knikkerlist;

	@Override
	/**
	 * Timeout wordt opgeslagen, wordt echter nog niks mee gedaan
	 */
	public void setTimeout(int time) {
		timeout = time;
	}

	@Override
	/**
	 * Probeert op een slimme manier een zet te bepalen.
	 * ten eerste wordt gekeken naar mogelijkheden om te winnen.
	 * Daarna of er verloren zal worden als 1 van de andere spelers aan de beurt is.
	 * Als dit zo is wordt er gekeken of dit voorkomen kan worden
	 * anders worden er punten toegekend aan vakjes op basis van een aantal regels en word de ze met de hoogste punten gedaan.
	 */
	public Zet getMove(Bord b, Knikker k) {
		Bord tempBord = new Bord();
		knikkerlist = new ArrayList<Knikker>(4);
		for (int i = 0; i < Bord.DIM; i++) {
			for (int j = 0; j < Bord.DIM; j++) {
				tempBord.getVeld(i, j).setKnikker(b.getVeld(i, j).getKnikker());
				if (tempBord.getVeld(i, j).getKnikker() != null
						&& !knikkerlist.contains(tempBord.getVeld(i, j)
								.getKnikker())) {
					knikkerlist.add(tempBord.getVeld(i, j).getKnikker());
				}
			}
		}
		if (k.getAantal() <= Spel.KNIKKERCOUNT - 4) {
			Zet tempzet = getWinZet(tempBord, k);
			if (tempzet != null) {
				System.out.println("Win");
				return tempzet;
			}
		}
		tempBord = new Bord();
		knikkerlist = new ArrayList<Knikker>(4);
		for (int i = 0; i < Bord.DIM; i++) {
			for (int j = 0; j < Bord.DIM; j++) {
				tempBord.getVeld(i, j).setKnikker(b.getVeld(i, j).getKnikker());
				if (tempBord.getVeld(i, j).getKnikker() != null
						&& !knikkerlist.contains(tempBord.getVeld(i, j)
								.getKnikker())) {
					knikkerlist.add(tempBord.getVeld(i, j).getKnikker());
				}
			}
		}
		if (k.getAantal() <= Spel.KNIKKERCOUNT - 3) {
			Zet tempzet = getNietVerliesZet(tempBord, k);
			if (tempzet != null) {
				return tempzet;
			}
		}
		tempBord = new Bord();
		knikkerlist = new ArrayList<Knikker>(4);
		for (int i = 0; i < Bord.DIM; i++) {
			for (int j = 0; j < Bord.DIM; j++) {
				tempBord.getVeld(i, j).setKnikker(b.getVeld(i, j).getKnikker());
				if (tempBord.getVeld(i, j).getKnikker() != null
						&& !knikkerlist.contains(tempBord.getVeld(i, j)
								.getKnikker())) {
					knikkerlist.add(tempBord.getVeld(i, j).getKnikker());
				}
			}
		}
		return determinePointBasedMove(b, k);
	}

	private Zet determinePointBasedMove(Bord b, Knikker k) {
		int centerValue = 3;
		int betweenvalue = 2;
		int[][] points = new int[Bord.DIM][Bord.DIM];
		points[4][4] += centerValue;
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				points[1 + 3 * i][1 + 3 * j] += centerValue;
				int xstart = (i == 0 ? i : i - 1);
				// checkt of het Veld aan de rechter kant van het bord ligt
				int xend = (i == 3 - 1 ? i : i + 1);
				// checkt of het Veld aan de bovenkant van het bord ligt
				int ystart = (j == 0 ? j : j - 1);
				// checkt of het Veld aan de onderkant van het bord ligt
				int yend = (j == 3 - 1 ? j : j + 1);
				if (b.getVeld(1+i*3, 1+3*j).getKnikker() == k) {
					for (int x = xstart; x <= xend; x++) {
						for (int y = ystart; y <= yend; y++) {
							if (b.getVeld(1 + 3 * x, 1 + 3 * y).getKnikker() == k) {
								int xdir = x-i;
								int ydir = y-j;
								for(int s = 1; s<=2;s++){
									points[i*3+1+s*xdir][j*3+1+s*ydir]+=betweenvalue;
								}
							}
						}
					}
				}

			}
		}
		for (int i = 0; i < Bord.DIM; i++) {
			for (int j = 0; j < Bord.DIM; j++) {

				points[i][j] += aantalBuren(i, j, k, b);

			}
		}

		int maxvalue = 0;
		List<int[]> positions = new ArrayList<int[]>();

		for (int i = 0; i < Bord.DIM; i++) {
			for (int j = 0; j < Bord.DIM; j++) {

				if (b.isLeegVeld(i, j)) {
					if (points[i][j] > maxvalue) {
						maxvalue = points[i][j];
						positions = new ArrayList<int[]>();
						positions.add(new int[] { i, j });
					} else if (points[i][j] == maxvalue) {
						positions.add(new int[] { i, j });
					}
				}
			}
		}
		int randindex = (int) (Math.random() * positions.size());
		Zet maxzet = new Zet(k, 0, 0, 0, Zet.Richting.Links);
		System.out.println("points: "+ maxvalue);
		maxzet.x = positions.get(randindex)[0];
		maxzet.y = positions.get(randindex)[1];
		maxzet.index = (int) (Math.random() * Bord.DIM);
		return maxzet;
	}

	private int aantalBuren(int x, int y, Knikker k, Bord b) {
		int aantal = 0;// -1 omdat het middelste

		if (k == null) {
			return aantal;
		}
		int xstart, xend, ystart, yend;
		// checkt of het Veld aan de linker kant van het bord ligt
		xstart = (x == 0 ? x : x - 1);
		// checkt of het Veld aan de rechter kant van het bord ligt
		xend = (x == Bord.DIM - 1 ? x : x + 1);
		// checkt of het Veld aan de bovenkant van het bord ligt
		ystart = (y == 0 ? y : y - 1);
		// checkt of het Veld aan de onderkant van het bord ligt
		yend = (y == Bord.DIM - 1 ? y : y + 1);

		// deze loop gaat door alle buren van het vakje, rekening houdend met de
		// grensen van het bord
		for (int i = xstart; i <= xend; i++) {
			for (int j = ystart; j <= yend; j++) {
				if (b.getVeld(i, j).getKnikker() == k) {
					aantal++;
				}
			}
		}
		// alle buren van dezelfde kleur
		return aantal;
	}

	private boolean canLose(Bord b, Knikker k) {
		boolean canlose = false;
		for (Knikker ek : knikkerlist) {
			if (ek != k) {
				if (getWinZet(b, ek) != null) {
					canlose = true;
				}
			}
		}
		return canlose;
	}

	private Zet getNietVerliesZet(Bord b, Knikker k) {
		Zet tempzet = null;
		boolean loseanyway = false;
		for (int i = 0; i < Bord.DIM; i++) {
			for (int j = 0; j < Bord.DIM; j++) {
				if (b.isLeegVeld(i, j)) {
					b.getVeld(i, j).setKnikker(k);
					for (int index = 0; index < Bord.DIM; index++) {
						b.DraaiSubBord(index, Zet.Richting.Rechts);
						if (!canLose(b, k)) {
							tempzet = new Zet(k, i, j, index,
									Zet.Richting.Rechts);
						} else {
							loseanyway = true;
						}
						b.DraaiSubBord(index, Zet.Richting.Links);
						b.DraaiSubBord(index, Zet.Richting.Links);
						if (!canLose(b, k)) {
							tempzet = new Zet(k, i, j, index,
									Zet.Richting.Links);
						} else {
							loseanyway = true;
						}
						b.DraaiSubBord(index, Zet.Richting.Rechts);
					}
					b.getVeld(i, j).setKnikker(null);
				}
			}
		}
		if (loseanyway) {
			System.out.println("Don't Lose");
			return tempzet;
		} else {
			return null;
		}

	}

	private Zet getWinZet(Bord b, Knikker k) {
		Zet tempzet = null;
		for (int i = 0; i < Bord.DIM && tempzet == null; i++) {
			for (int j = 0; j < Bord.DIM && tempzet == null; j++) {
				if (b.isLeegVeld(i, j)) {
					b.getVeld(i, j).setKnikker(k);
					if (b.isWinnaar().contains(k.getSpeler())) {
						tempzet = new Zet(k, i, j, 0, Zet.Richting.Links);
					}
					for (int index = 0; index < Bord.DIM && tempzet == null; index++) {
						b.DraaiSubBord(index, Zet.Richting.Rechts);
						if (b.isWinnaar().contains(k.getSpeler())) {
							tempzet = new Zet(k, i, j, index,
									Zet.Richting.Rechts);
						}
						b.DraaiSubBord(index, Zet.Richting.Links);
						b.DraaiSubBord(index, Zet.Richting.Links);
						if (b.isWinnaar().contains(k.getSpeler())) {
							tempzet = new Zet(k, i, j, index,
									Zet.Richting.Links);
						}
						b.DraaiSubBord(index, Zet.Richting.Rechts);
					}
					b.getVeld(i, j).setKnikker(null);
				}
			}
		}

		return tempzet;
	}
}
